package ss.pku.jsa.worklist;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import ss.pku.jsa.worklist.om.Constraint;
import ss.pku.jsa.worklist.om.Value;
import ss.pku.jsa.worklist.sethelper.SetEqualHelper;
import ss.pku.jsa.worklist.util.InfluenceGenerator;

public abstract class WorkListTemplate<M, K> {
	private Constraint<M, K>[] constraints;
	private Map<M, Set<Constraint<M, K>>> infl;

	public WorkListTemplate(Constraint<M, K>[] constraints) {
		this.constraints = constraints;
	}

	public Map<M, Set<Value<M, K>>> executeAnalysis() {
		for (Constraint<M, K> constraint : constraints) {
			this.insert(constraint);
		}

		Map<M, Set<Value<M, K>>> result = new HashMap<M, Set<Value<M, K>>>();
		for (Constraint<M, K> constraint : constraints) {
			result.put(constraint.getLeft().getNode(), constraint.getLeft()
					.getValues());
		}
		infl = InfluenceGenerator.generate(constraints);
		Constraint<M, K> constraint = null;
		while ((constraint = extract()) != null) {
			Set<Value<M, K>> newValue = eval(constraint);
			if (!SetEqualHelper.equals(newValue,
					result.get(constraint.getLeft().getNode()))) {
				result.put(constraint.getLeft().getNode(), newValue);
				Set<Constraint<M, K>> inflSet = infl.get(constraint.getLeft()
						.getNode());
				for (Constraint<M, K> tobecalc : inflSet) {
					insert(tobecalc);
				}
			}
		}
		return result;
	}

	public abstract Set<Value<M, K>> eval(Constraint<M, K> constraint);

	public abstract void insert(Constraint<M, K> constraint);

	public abstract Constraint<M, K> extract();

}
